热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

宿主|可能会_Android架构组件之ViewModel

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android架构组件之ViewModel相关的知识,希望对你有一定的参考价值。ViewModel概念及用途

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android架构组件之ViewModel相关的知识,希望对你有一定的参考价值。



ViewModel概念及用途

ViewModel用来存储和管理UI相关的数据,可于将一个Activity或Fragment组件相关的数据逻辑抽象出来,并能适配组件的生命周期,如当屏幕旋转Activity重建后,ViewModel中的数据依然有效。

引入ViewModel之前,存在如下几个问题:


  1. 通常android系统来管理UI controllers(如Activity、Fragment)的生命周期,由系统响应用户交互或者重建组件,用户无法操控。当组件被销毁并重建后,原来组件相关的数据也会丢失,如果数据类型比较简单,同时数据量也不大,可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,不方便序列化及反序列化,则上述方法将不适用。
  2. UI controllers经常会发送很多异步请求,有可能会出现UI组件已销毁,而请求还未返回的情况,因此UI controllers需要做额外的工作以防止内存泄露。
  3. 当Activity因为配置变化而销毁重建时,一般数据会重新请求,其实这是一种浪费,最好就是能够保留上次的数据。
  4. UI controllers其实只需要负责展示UI数据、响应用户交互和系统交互即可。但往往开发者会在Activity或Fragment中写许多数据请求和处理的工作,造成UI controllers类代码膨胀,也会导致单元测试难以进行。我们应该遵循职责分离原则,将数据相关的事情从UI controllers中分离出来。

上述几个痛点正是ViewModel出现的原因。


ViewModel使用方式

Android架构组件提供了一个ViewModel帮助类来为UI controllers负责数据相关的工作,当配置变化组件销毁重建时,这些数据仍然可以保留。当新的组件重建后,可以立即使用之前保留的数据。下面的示例代码维护了一个User列表数据:

public class MyViewModel extends ViewModel
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers()
if (users &#61;&#61; null)
users &#61; new MutableLiveData<List<Users>>();
loadUsers();

return users;

private void loadUsers()
// Do an asyncronous operation to fetch users.


在Activity中可以按如下方式使用ViewModel&#xff1a;

public class MyActivity extends AppCompatActivity
public void onCreate(Bundle savedInstanceState)
// Create a ViewModel the first time the system calls an activity&#39;s onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
MyViewModel model &#61; ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users ->
// update UI
);


如果Activity销毁重建&#xff0c;可以立即得到一个相同的MyViewModel实例&#xff0c;它是由之前销毁的Activity创建的。当宿主Activity最终销毁后&#xff0c;系统会调用ViewModel的onCleared()方法来释放资源。

由上面的例子可以知道&#xff0c;ViewModel的生命周期比特定viewLifecycleOwner&#xff08;如Activity实现了LifecycleOwner接口&#xff09;要长&#xff0c;因此ViewModel不要引用viewLifecycle或其他引用到Activity上下文的对象。

ViewModel中可以包含LifecycleObserver&#xff0c;如LiveData对象。如果ViewModel需要使用Application的上下文对象&#xff0c;则可以通过继承AndroidViewModel&#xff0c;并提供一个以Application为参数的构造函数。


ViewModel的生命周期

ViewModel的生命周期依赖于对应的Activity或Fragment的生命周期。通常会在Activity第一次onCreate()时创建ViewModel&#xff0c;ViewModel的生命周期一直持续到Activity最终销毁或Frament最终detached&#xff0c;期间由于屏幕旋转等配置变化引起的Activity销毁重建并不会导致ViewModel重建。借用官方示意图来解释一下&#xff1a;

上图左侧为Activity的生命周期过程&#xff0c;期间有一个旋转屏幕的操作&#xff1b;右侧则为ViewModel的生命周期过程。

一般通过如下代码初始化ViewModel&#xff1a;

viewModel &#61; ViewModelProviders.of(this).get(UserProfileViewModel.class);

this参数一般为Activity或Fragment&#xff0c;因此ViewModelProvider可以获取组件的生命周期。

Activity在生命周期中可能会触发多次onCreate()&#xff0c;而ViewModel则只会在第一次onCreate()时创建&#xff0c;然后直到最后Activity销毁。


Fragment之间分享数据

日常开发中&#xff0c;一个Activity中可能会有多个Fragment&#xff0c;且他们需要进行交互。例如一个Fragment展示列表&#xff0c;另一个Fragment展示选中列表对应的详情信息&#xff0c;之前我们可能会利用宿主Activity并定义几个接口来实现Fragment之间的交互&#xff0c;另外还得考虑Fragment是否已经创建或显示的问题。

上述痛点&#xff0c;可以使用ViewModel来解决&#xff0c;在Fragment之间可以共享ViewModel。示例代码如下&#xff1a;

public class SharedViewModel extends ViewModel
private final MutableLiveData<Item> selected &#61; new MutableLiveData<Item>();
public void select(Item item)
selected.setValue(item);

public LiveData<Item> getSelected()
return selected;


public class MasterFragment extends Fragment
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
model &#61; ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item ->
model.select(item);
);


public class DetailFragment extends Fragment
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
SharedViewModel model &#61; ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item ->
// Update the UI.
);


注意到上面两个Fragment都用到了如下代码来获取ViewModel&#xff1a;

SharedViewModel model &#61; ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

getActivity()返回的是同一个宿主Activity&#xff0c;因此两个Fragment之间返回的是同一个SharedViewModel对象。

Fragment间共享ViewModel的优点有&#xff1a;


  1. 宿主Activity不需要做任何事情&#xff0c;也不需要关心Fragment间交互的内容。
  2. Fragment只需要了解ViewModel的实现&#xff0c;而无需了解通信目标Fragment。即使一个Fragment已经销毁了&#xff0c;另一个Fragment也能正常工作。
  3. 每一个Fragment有自己的生命周期&#xff0c;并不受其他Fragment影响。
  4. Fragment之间解耦。

总结


  1. ViewModel职责是为Activity或Fragment管理、请求数据&#xff0c;当然具体数据请求逻辑不应该写在ViewModel中&#xff0c;否则ViewModel的职责会变得太重&#xff0c;此处需要一个引入一个Repository&#xff0c;负责数据请求相关工作。具体请参考 Android架构组件。
  2. ViewModel可以用于Activity内不同Fragment的交互&#xff0c;也可以用作Fragment之间一种解耦方式。
  3. ViewModel也可以负责处理部分Activity/Fragment与应用其他模块的交互。
  4. ViewModel生命周期&#xff08;以Activity为例&#xff09;起始于Activity第一次onCreate()&#xff0c;结束于Activity最终finish时。

参考&#xff1a;
https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html

我的微信公众号「不混青年」&#xff0c;id「buhunqingnian」&#xff0c;技术之外的分享&#xff1a;


推荐阅读
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
author-avatar
霞慧水灵灵_973
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有